package com.aabte.nettyleran.netty.privateprotocolstack;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.timeout.ReadTimeoutHandler;

import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author Daniel
 * @version 1.0
 * @date 2020/3/15
 */
public class NettyClient {

    private static final ExecutorService executor = new ThreadPoolExecutor(10, 10, 10L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());

    public static final String REMOTE_IP = "127.0.0.1";
    public static final int REMOTE_PORT = 8080;
    public static final String LOCAL_IP = "127.0.0.1";
    public static final int LOCAL_PORT = 8082;

    public static void main(String[] args) throws InterruptedException {
        new NettyClient().connect(REMOTE_IP, REMOTE_PORT);
    }

    private void connect(String host, final int port) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast("netty-message-decoder", new NettyMessageDecoder(1024 * 1024, 0, 4, 0, 4));
                        socketChannel.pipeline().addLast(new LengthFieldPrepender(4));
                        socketChannel.pipeline().addLast("netty-message-encoder", new NettyMessageEncoder());
                        socketChannel.pipeline().addLast("read-timeout-handler", new ReadTimeoutHandler(50));
                        socketChannel.pipeline().addLast("login-auth-req-handler", new LoginAuthReqHandler());
                        socketChannel.pipeline().addLast("heart-beat-handler", new HeartBeatReqHandler());
                    }
                });

        try {
            ChannelFuture channelFuture = bootstrap.connect(
                    new InetSocketAddress(host, port)
                    , new InetSocketAddress(LOCAL_IP, LOCAL_PORT)
            )
                    .sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            executor.execute(() -> {
                try {
                    TimeUnit.SECONDS.sleep(5);
                    // 重连
                    try {
                        connect(host, port);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}
